# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: jaewon

import datetime
import importlib
import logging

from coin.base.datetime_util import to_datetime
from coin.base.param_util import to_list
from coin.strategy.mm.subscription import FeedSubscriptionRequest
from coin.strategy.mm.dumper_base import run_from_archive


def get_profile_module(profile_name, profile_args, ref_ts=None):
  if profile_name.endswith('.py'):
    profile_name = profile_name[:-3]
  profile_name = profile_name.replace('/', '.')

  module_prefix = 'coin.strategy.mm.simple_sim.profile.'
  module_name = profile_name
  if not profile_name.startswith(module_prefix):
    module_name = module_prefix + profile_name

  try:
    module = importlib.import_module(module_name)
  except ModuleNotFoundError:
    logging.fatal('Profile module <%s> not found or error occured during import', module_name)
    raise

  if 'prepare' in dir(module):
    ref_ts = to_datetime(ref_ts or datetime.datetime.now())
    module.prepare(profile_args, ref_ts)
  else:
    assert not profile_args, ('Profile <%s> does not support arguments' % module_name)

  return module


def run_sim_strategy(profile_name,
                     from_ts,
                     to_ts,
                     from_index_inclusive=None,
                     to_index_inclusive=None,
                     root_dir=None,
                     profile_args=None,
                     from_feed_cache=False,
                     feed_cache_dir=None):
  profile = get_profile_module(profile_name, profile_args, from_ts)

  try:
    feed_sub_request = profile.get_feed_sub_request(from_ts)
  except Exception:
    feed_sub_request = None

  if feed_sub_request is None:
    try:
      products = to_list(profile.get_products())
    except TypeError:
      products = to_list(profile.get_products(from_ts))

  try:
    machines = to_list(profile.get_machines())
  except TypeError:
    machines = to_list(profile.get_machines(from_ts))

  strategies = to_list(profile.get_strategy(from_ts, to_ts))
  if from_index_inclusive is not None or to_index_inclusive is not None:
    to_index = to_index_inclusive + 1 if to_index_inclusive is not None else None
    strategies = strategies[from_index_inclusive:to_index]

  for s in strategies:
    if hasattr(s, 'init'):
      s.init()

  if from_feed_cache:
    import coin.strategy.mm.fastfeature.feed_cache_gen_for_fastfeature as fcgff
    try:
      import coin.feed.fastfeed.native_wrapper as nwrp
    except (ImportError, ModuleNotFoundError):
      logging.warning('Unable to import native module.')

    nwrp.run_from_feed_cache(feed_sub_request or products, [s.on_book_reset for s in strategies],
                             from_ts,
                             to_ts,
                             machine=machines,
                             feed_cache_dir=feed_cache_dir,
                             worker_id='1')
  else:
    run_from_archive(products, [s.on_book_reset for s in strategies],
                     from_ts,
                     to_ts,
                     machine=machines,
                     root_dir=root_dir,
                     worker_id='1')

  return [profile.get_strategy_result(s) for s in strategies]


def get_num_strategies(profile, from_ts, to_ts):
  # TODO(jaewon): Better implementation
  strategies = profile.get_strategy(from_ts, to_ts)
  return len(strategies)
